import os
import subprocess
import re
import argparse
import json
import tempfile
import shutil
from datetime import datetime, timedelta

def parse_time(time_str):
    """将时间字符串转换为秒数"""
    try:
        if '.' in time_str:
            time_obj = datetime.strptime(time_str, "%H:%M:%S.%f")
        else:
            time_obj = datetime.strptime(time_str, "%H:%M:%S")
        return time_obj.hour * 3600 + time_obj.minute * 60 + time_obj.second + time_obj.microsecond / 1000000
    except ValueError:
        try:
            return float(time_str)
        except:
            return 0

def format_time(seconds):
    """将秒数格式化为 HH:MM:SS.ms """
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    seconds_remainder = seconds % 60
    milliseconds = int((seconds_remainder - int(seconds_remainder)) * 1000)
    return f"{hours:02d}:{minutes:02d}:{int(seconds_remainder):02d}.{milliseconds:03d}"

def get_video_duration(input_file):
    """获取视频总时长（秒）"""
    try:
        cmd = [
            'ffprobe',
            '-v', 'error',
            '-show_entries', 'format=duration',
            '-of', 'json',
            input_file
        ]
        
        result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        data = json.loads(result.stdout)
        return float(data['format']['duration'])
    except Exception:
        return 0

def read_frozen_intervals(file_path):
    """读取静止画面区间文件"""
    intervals = []
    total_frozen = 0
    frozen_percent = 0
    
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            lines = f.readlines()
            
            for line in lines:
                # 跳过标题行和空行
                if line.startswith('开始时间') or line.startswith('开始时间') or line.strip() == '':
                    continue
                
                # 检查总静止时间行
                if '总静止画面时间' in line or '总静止时间' in line:
                    match = re.search(r'总静止.*?时间: (\d+\.?\d*)秒', line)
                    if match:
                        total_frozen = float(match.group(1))
                    match = re.search(r'\((\d+\.?\d*)%\)', line)
                    if match:
                        frozen_percent = float(match.group(1))
                    continue
                
                # 解析区间行
                parts = re.split(r'\s+', line.strip())
                if len(parts) >= 2:
                    start = parse_time(parts[0])
                    end = parse_time(parts[1])
                    if start < end and (end - start) > 0.1:  # 忽略小于0.1秒的区间
                        intervals.append((start, end))
        
        # 按开始时间排序
        intervals.sort(key=lambda x: x[0])

        # 合并重叠或相邻的区间
        if not intervals:
            return [], total_frozen, frozen_percent
            
        merged_intervals = [intervals[0]]
        for current_start, current_end in intervals[1:]:
            last_start, last_end = merged_intervals[-1]
            
            # 如果当前区间与上一个区间重叠或相邻，则合并
            if current_start <= last_end + 0.5:  # 允许0.5秒的间隙
                merged_intervals[-1] = (last_start, max(last_end, current_end))
            else:
                merged_intervals.append((current_start, current_end))
        
        return merged_intervals, total_frozen, frozen_percent

    except Exception as e:
        print(f"读取静止画面区间文件出错: {str(e)}")
        return [], 0, 0

def create_keep_intervals(frozen_intervals, total_duration):
    """根据静止画面区间创建需要保留的区间"""
    keep_intervals = []
    
    # 如果没有静止画面区间，保留整个视频
    if not frozen_intervals:
        return [(0, total_duration)]
    
    # 第一个保留区间：从0到第一个静止画面开始
    if frozen_intervals[0][0] > 0:
        keep_intervals.append((0, frozen_intervals[0][0]))
    
    # 中间保留区间：静止画面结束到下一个静止画面开始
    for i in range(len(frozen_intervals) - 1):
        end_current = frozen_intervals[i][1]
        start_next = frozen_intervals[i+1][0]
        
        # 确保有间隙
        if end_current < start_next:
            keep_intervals.append((end_current, start_next))
    
    # 最后一个保留区间：最后一个静止画面结束到视频结束
    if frozen_intervals[-1][1] < total_duration:
        keep_intervals.append((frozen_intervals[-1][1], total_duration))
    
    # 合并相邻或重叠的保留区间
    if not keep_intervals:
        return []
    
    merged_intervals = [keep_intervals[0]]
    for current_start, current_end in keep_intervals[1:]:
        last_start, last_end = merged_intervals[-1]
        
        # 如果当前区间与上一个区间重叠或相邻，则合并
        if current_start <= last_end + 0.5:  # 允许0.5秒的间隙
            merged_intervals[-1] = (last_start, max(last_end, current_end))
        else:
            merged_intervals.append((current_start, current_end))
    
    return merged_intervals

def find_keyframe_near_time(input_file, time_point):
    """在指定时间点附近查找最近的关键帧"""
    try:
        cmd = [
            'ffprobe',
            '-v', 'error',
            '-skip_frame', 'nokey',
            '-select_streams', 'v:0',
            '-show_entries', 'frame=best_effort_timestamp_time',
            '-of', 'csv=p=0',
            '-read_intervals', f'{max(0, time_point-1)}%{time_point+1}',
            input_file
        ]
        
        result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        keyframes = [float(line.strip()) for line in result.stdout.splitlines() if line.strip()]
        
        if not keyframes:
            return time_point
            
        # 找到最接近指定时间的关键帧
        closest = min(keyframes, key=lambda x: abs(x - time_point))
        return closest
        
    except Exception:
        return time_point

def cut_with_segments(input_file, output_file, keep_intervals, overwrite, total_duration):
    """使用分段处理方法裁剪视频"""
    temp_dir = tempfile.mkdtemp()
    segment_files = []
    
    try:
        print("使用分段处理方法...")
        
        # 创建每个保留区间的片段
        for i, (start, end) in enumerate(keep_intervals):
            # 查找最近的关键帧
            keyframe_start = find_keyframe_near_time(input_file, start)
            keyframe_end = find_keyframe_near_time(input_file, end)
            
            # 确保开始时间不超过结束时间
            if keyframe_start >= keyframe_end:
                print(f"警告: 跳过无效区间 {format_time(start)} - {format_time(end)} (关键帧对齐后无效)")
                continue
                
            segment_file = os.path.join(temp_dir, f"segment_{i:04d}.mp4")
            segment_files.append(segment_file)
            
            duration = keyframe_end - keyframe_start
            print(f"创建片段 {i+1}/{len(keep_intervals)}: {format_time(start)} -> {format_time(keyframe_start)} - {format_time(end)} -> {format_time(keyframe_end)} ({duration:.2f}秒)")
            
            cmd = [
                'ffmpeg',
                '-ss', str(keyframe_start),
                '-i', input_file,
                '-t', str(duration),
                '-c', 'copy',  # 复制流，不重新编码
                '-avoid_negative_ts', 'make_zero',
                '-y',
                segment_file
            ]
            
            result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            if result.returncode != 0:
                print(f"创建片段失败: {result.stderr.decode()}")
                return False
        
        if not segment_files:
            print("错误: 没有有效的片段可合并")
            return False
        
        # 创建文件列表
        list_file = os.path.join(temp_dir, "filelist.txt")
        with open(list_file, 'w', encoding='utf-8') as f:
            for segment_file in segment_files:
                f.write(f"file '{os.path.basename(segment_file)}'\n")
        
        # 合并所有片段
        print("合并片段...")
        cmd = [
            'ffmpeg',
            '-f', 'concat',
            '-safe', '0',
            '-i', list_file,
            '-c', 'copy',  # 复制流，不重新编码
            '-movflags', '+faststart',
            '-y' if overwrite else '-n',
            output_file
        ]
        
        # 切换到临时目录执行合并命令
        original_dir = os.getcwd()
        os.chdir(temp_dir)
        
        result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        
        # 切换回原目录
        os.chdir(original_dir)
        
        if result.returncode == 0:
            # 获取新视频时长
            new_duration = get_video_duration(output_file)
            print(f"裁剪成功: {input_file} -> {output_file}")
            print(f"原始时长: {total_duration:.2f}秒, 新时长: {new_duration:.2f}秒, 裁剪了 {total_duration - new_duration:.2f}秒")
            return True
        else:
            print(f"合并片段失败: {result.stderr.decode()}")
            return False
            
    except Exception as e:
        print(f"分段处理过程中出错: {str(e)}")
        return False
    finally:
        # 清理临时文件
        if os.path.exists(temp_dir):
            shutil.rmtree(temp_dir)

def cut_video_frozen_frames(input_file, output_file, frozen_file, overwrite=False, method='precise'):
    """
    裁剪视频中的静止画面部分
    
    参数:
    input_file: 输入视频文件路径
    output_file: 输出视频文件路径
    frozen_file: 静止画面区间文件路径
    overwrite: 是否覆盖已存在的输出文件
    method: 裁剪方法 ('fast'或'precise')
    """
    # 获取视频总时长
    total_duration = get_video_duration(input_file)
    
    # 读取静止画面区间
    frozen_intervals, total_frozen, frozen_percent = read_frozen_intervals(frozen_file)
    
    if not frozen_intervals:
        print("未检测到静止画面区间，无需裁剪")
        return False
    
    # 创建需要保留的区间
    keep_intervals = create_keep_intervals(frozen_intervals, total_duration)
    
    if not keep_intervals:
        print("没有需要保留的区间，可能是静止画面区间覆盖了整个视频")
        return False
    
    print(f"视频总时长: {total_duration:.2f}秒")
    print(f"检测到静止画面区间: {len(frozen_intervals)}个")
    print(f"总静止画面时间: {total_frozen:.2f}秒 ({frozen_percent:.2f}%)")
    print(f"将保留 {len(keep_intervals)} 个非静止画面区间")
    
    # 显示保留区间信息
    print("\n保留区间:")
    for i, (start, end) in enumerate(keep_intervals):
        duration = end - start
        position = (start / total_duration * 100) if total_duration > 0 else 0
        print(f"  区间 {i+1}: {format_time(start)} - {format_time(end)} ({duration:.2f}秒, {position:.1f}%)")
    
    # 使用分段处理方法（更稳定）
    return cut_with_segments(input_file, output_file, keep_intervals, overwrite, total_duration)

def main():
    parser = argparse.ArgumentParser(description='裁剪视频中的静止画面部分')
    parser.add_argument('input', help='输入视频文件路径')
    parser.add_argument('frozen_file', help='静止画面区间文件路径')
    parser.add_argument('-o', '--output', help='输出视频文件路径（默认为输入文件加_cut后缀）')
    parser.add_argument('-y', '--overwrite', action='store_true', help='覆盖已存在的输出文件')
    parser.add_argument('-m', '--method', choices=['fast', 'precise'], default='precise',
                        help='裁剪方法: fast(快速,适用于较少区间)或precise(精确,适用于较多区间)')
    
    args = parser.parse_args()
    
    # 设置默认输出文件名
    if args.output is None:
        filename, ext = os.path.splitext(args.input)
        args.output = f"{filename}_cut{ext}"
    
    # 检查输入文件是否存在
    if not os.path.isfile(args.input):
        print(f"错误: 输入视频文件不存在 - {args.input}")
        return
    
    if not os.path.isfile(args.frozen_file):
        print(f"错误: 静止画面区间文件不存在 - {args.frozen_file}")
        return
    
    # 删除已存在的输出文件
    if os.path.isfile(args.output):
        if args.overwrite:
            os.remove(args.output)
        else:
            print(f"错误: 输出文件已存在 - {args.output} (使用 -y 选项覆盖)")
            return
    
    print(f"输入视频: {args.input}")
    print(f"静止画面区间文件: {args.frozen_file}")
    print(f"输出视频: {args.output}")
    print(f"裁剪方法: {args.method}")
    
    success = cut_video_frozen_frames(
        input_file=args.input,
        output_file=args.output,
        frozen_file=args.frozen_file,
        overwrite=args.overwrite,
        method=args.method
    )
    
    if success:
        print("视频裁剪完成!")
    else:
        print("视频裁剪失败")

if __name__ == "__main__":
    main()